package com.soenkerohde.logging
{
	import com.shinderlin.*;
	
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.XMLSocket;
	
	import mx.logging.ILogger;
	import mx.logging.LogEventLevel;

	/**
	 * @author Sönke Rohde (opensource@soenkerohde.com, http://soenkerohde.com)
	 * @license LGPL (http://www.gnu.org/licenses/lgpl.html)
	 *
	 * This logging class targets SOS: http://sos.powerflasher.com
	 *  
	 * the category is the source of the logging.
	 * you can construct the Logger with a reference (this) or a String
	 * 
	 */

	public class SOSLogger implements ILogger
	{

		public static var clearOnConnect : Boolean = true;
		private static var socket : XMLSocket = new XMLSocket();
		private static var history : Array = new Array();
		private var _category : Object;
		private var dispatcher : EventDispatcher;

		private var TERMINATOR : String = "\n";

		/**
		 * Variable: COL_FATAL
		 * The colour of the background of log messages with a severity of FATAL
		 **/
		private static var COL_FATAL : Number = 0xFF0000;
		/**
		 * Variable: COL_ERROR
		 * The colour of the background of log messages with a severity of ERROR
		 **/
		private static var COL_ERROR : Number = 0xFF6666;
		/**
		 * Variable: COL_WARN
		 * The colour of the background of log messages with a severity of WARN
		 **/
		private static var COL_WARN : Number = 0xFFCCCC;
		/**
		 * Variable: COL_INFO
		 * The colour of the background of log messages with a severity of INFO
		 **/
		private static var COL_INFO : Number = 0xDDDDDD;
		/**
		 * Variable: COL_DEBUG
		 * The colour of the background of log messages with a severity of DEBUG
		 **/
		private static var COL_DEBUG : Number = 0xFFFFFF;
		
		/**
		 * Variable: logHost
		 * The host to connect to for logging
		 **/
		private var logHost:String = "localhost";

		/**
		 * Variable: logPort
		 * The port to connect to for logging
		 **/
		private var logPort:int = 4445;
		
		 
		public function SOSLogger( _category : Object )
		{
			this._category = _category;
		}

		private function send( level : int, _category : Object, message : * ) : void
		{
			if ( socket.connected )
			{
				var type : String;
				var tracePrefix : String;
				switch( level )
				{
					case LogEventLevel.DEBUG :
						type = "DEBUG";
						tracePrefix = "_";
						break;
					case LogEventLevel.INFO :
						type = "INFO";
						tracePrefix = "-";
						break;
					case LogEventLevel.WARN :
						type = "WARN";
						tracePrefix = "!";
						break;
					case LogEventLevel.ERROR :
						type = "ERROR";
						tracePrefix = "#";
						break;
					case LogEventLevel.FATAL :
						type = "FATAL";
						tracePrefix = "µ";
						break;
					default:
						trace("default");
						type = "INFO";
				}
				message = _category + "->" + message;
				trace(tracePrefix + " " + message);
	
/*				
				var txt : String = "";
				//if (e.loggerId) txt += e.loggerId;
				if (type.toUpperCase()) txt += "[" + type.toUpperCase() + "]";
				txt += ":";
				txt += QopDump.echo(message);
				var txtSplit : Array = txt.split("\n");
				if (txtSplit.length == 1) 
				{
					_sendCommand("<showMessage key=\"" + type.toUpperCase() + "\"><![CDATA[" + txt + "]]></showMessage>");
				} else 
				{
					var firstLine : String = txtSplit[0];
					_sendCommand("<showFoldMessage key=\"" + type.toUpperCase() + "\"><title><![CDATA[" + firstLine + "]]></title><message><![CDATA[" + txtSplit.splice(1).join("\n") + "]]></message></showFoldMessage>");
				}
*/				
				message  = '[' + type.toUpperCase() + ']' + message;
				var xmlMessage : String = '<showMessage key="' + type.toUpperCase() + '"> <![CDATA[' + message + ']]></showMessage>';
				socket.send(xmlMessage + "\n");
			} 
			else
			{
				if( !socket.hasEventListener("connect") )
				{
					socket.addEventListener("connect", onSocket);
				}
				
				socket.addEventListener(IOErrorEvent.IO_ERROR, ioErrorListener);
				socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorListener);
				
				socket.connect(logHost, logPort);
				
				var appName : String = "DEBUGGER";
				_sendCommand("<appName>" + appName + "</appName>");
				_sendCommand("<setKey><name>FATAL</name><color>" + COL_FATAL + "</color></setKey>");
				_sendCommand("<setKey><name>ERROR</name><color>" + COL_ERROR + "</color></setKey>");
				_sendCommand("<setKey><name>WARN</name><color>" + COL_WARN + "</color></setKey>");
				_sendCommand("<setKey><name>INFO</name><color>" + COL_INFO + "</color></setKey>");
				_sendCommand("<setKey><name>DEBUG</name><color>" + COL_DEBUG + "</color></setKey>");
				
				var o : Object = new Object();
				o.level = level;
				o.category = _category;
				o.message = message;
				history.push(o);
			}
		}


		public function debug(message : String, ... rest : Array) : void
		{
			send(LogEventLevel.DEBUG, _category, message);
		}

		public function info(message : String, ... rest : Array) : void
		{
			send(LogEventLevel.INFO, _category, message);
		}

		public function warn(message : String, ... rest : Array) : void
		{
			send(LogEventLevel.WARN, _category, message);
		}

		public function error(message : String, ... rest : Array) : void
		{
			send(LogEventLevel.ERROR, _category, message);
		}

		public function fatal(message : String, ... rest : Array) : void
		{
			send(LogEventLevel.FATAL, _category, message);
		}

		public function log(level : int, message : String, ... rest : Array) : void
		{
			send(level, _category, message);
		}

		public function get category() : String
		{
			return _category.toString();
		}

		public function hasEventListener(type : String) : Boolean
		{
			return dispatcher.hasEventListener(type);
		}

		public function willTrigger(type : String) : Boolean
		{
			return dispatcher.willTrigger(type);
		}

		public function addEventListener(type : String, listener : Function, useCapture : Boolean = false, priority : int = 0.0, useWeakReference : Boolean = false) : void
		{
			dispatcher.addEventListener(type, listener, useCapture, priority, useWeakReference);
		}

		public function removeEventListener(type : String, listener : Function, useCapture : Boolean = false) : void
		{
			dispatcher.removeEventListener(type, listener, useCapture);
		}

		public function dispatchEvent(event : Event) : Boolean
		{
			return dispatcher.dispatchEvent(event);
		}
		
		public function getLogHost():String
		{
			return logHost;
		}
		public function setLogHost(newLogHost:String):void
		{
			logHost = newLogHost;
		}
		
		public function getLogPort():int
		{
			return logPort;
		}
		public function setLogPort(newLogPort:int):void
		{
			logPort = newLogPort;	
		}
		
		private function _sendCommand(command : String):void
		{
			// comment out the following line if you set sosPort to be the Command-Port...
			//command = "!SOS"+command;
			socket.send(command + TERMINATOR);
		}
		
		private function ioErrorListener(e:IOErrorEvent):void
		{
			trace("[SOSLogger] : IOErrorEvent while trying to connect to socket server");	
		}
		
		private function securityErrorListener(e:SecurityErrorEvent):void
		{
			trace("[SOSLogger] : SecurityErrorEvent while trying to connect to socket server");	
		}
		
		private function onSocket(e : Event) : void
		{
			if( clearOnConnect )
			{
				socket.send('<clear/>\n');
			}
			for each( var o:Object in history )
			{
				send(o.level, o.category, o.message);
			}
		}
	}
}